-
Notifications
You must be signed in to change notification settings - Fork 140
feat(gemini): add secure Gemini API SDK setup for backend and frontend #143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds Gemini API integration: new backend FastAPI Changes
Sequence DiagramsequenceDiagram
participant User
participant Frontend as Frontend (Next.js)
participant Backend as Backend (FastAPI)
participant GeminiAPI as Gemini API
User->>Frontend: Enter prompt
Frontend->>Frontend: generateGeminiText(prompt)
Frontend->>Backend: POST /generate { prompt }
Backend->>Backend: Check gemini_api_key
alt key present
Backend->>GeminiAPI: POST /v1beta/generateContent (30s)
alt success
GeminiAPI-->>Backend: 200 + JSON
Backend-->>Frontend: 200 + JSON
Frontend-->>User: Display response
else failure
GeminiAPI-->>Backend: Error
Backend-->>Frontend: 502 Bad Gateway
Frontend-->>User: Show error
end
else key missing
Backend-->>Frontend: 500 Internal Server Error
Frontend-->>User: Show error
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
backend/app/gemini_client.js(1 hunks)backend/env_example(1 hunks)frontend/.env.example(1 hunks)frontend/lib/geminiClient.ts(1 hunks)guides/summaries/Gemini_codegen_guide(1 hunks)
🧰 Additional context used
🪛 dotenv-linter (4.0.0)
frontend/.env.example
[warning] 6-6: [UnorderedKey] The GEMINI_API_KEY key should go before the NEXT_PUBLIC_API_URL key
(UnorderedKey)
🔇 Additional comments (3)
backend/env_example (1)
22-24: LGTM!The addition of
GEMINI_API_KEYto the backend environment configuration is appropriate. Backend environment variables are not exposed to the browser, making this a safe location for the API key.guides/summaries/Gemini_codegen_guide (1)
1-679: Excellent comprehensive guide!This documentation provides thorough guidance on Gemini API usage, including initialization patterns, model selection, and various use cases. It serves as a valuable reference for the team implementing Gemini features.
frontend/.env.example (1)
6-6: No architectural clarification needed—geminiClient.tsis currently unused.Verification reveals that
frontend/lib/geminiClient.tsexists but is not imported anywhere in the codebase. The file is dead code. TheGEMINI_API_KEYconfiguration infrontend/.env.example(line 6, without theNEXT_PUBLIC_prefix) is correctly structured for server-side-only access, which is the secure approach for API keys.Since
geminiClient.tshas zero active usage, there is no architectural concern to clarify at this time. When this module is actually integrated and imported, the appropriate pattern should be:
- Keep
GEMINI_API_KEYserver-side only (as currently configured)- Use from server-side contexts only (API routes, server components, etc.)
The static configuration is correct as-is.
Likely an incorrect or invalid review comment.
backend/app/gemini_client.js
Outdated
| import { GoogleGenAI } from "@google/genai"; | ||
|
|
||
| // Uses the GEMINI_API_KEY environment variable if apiKey not specified | ||
| const ai = new GoogleGenAI({}); | ||
|
|
||
| export default ai; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify the @google/genai dependency is installed.
The implementation correctly follows the SDK initialization pattern. However, ensure that the @google/genai package is installed in the backend dependencies.
Run the following script to verify the dependency installation:
🏁 Script executed:
#!/bin/bash
# Description: Verify @google/genai is listed in backend package.json dependencies
# Check if @google/genai is in backend package.json
if [ -f "backend/package.json" ]; then
echo "=== Checking backend/package.json ==="
cat backend/package.json | jq '.dependencies["@google/genai"], .devDependencies["@google/genai"]' 2>/dev/null || grep -A2 -B2 "@google/genai" backend/package.json
else
echo "ERROR: backend/package.json not found"
fiLength of output: 37
---
🏁 Script executed:
```shell
#!/bin/bash
# Find all package.json files to understand project structure
echo "=== Locating package.json files ==="
fd -t f "package.json"
echo ""
echo "=== Checking for backend/app/gemini_client.js ==="
fd -t f "gemini_client.js"
echo ""
echo "=== Project root structure ==="
fd -t f -d 2 "package.json|yarn.lock|pnpm-lock.yaml" | head -20
Length of output: 191
---
🏁 Script executed:
```shell
#!/bin/bash
# Check for root-level package.json and other dependency files
echo "=== Root-level package/dependency files ==="
fd -t f -d 1 "package.json|package-lock.json|yarn.lock|pnpm-lock.yaml|requirements.txt|go.mod"
echo ""
echo "=== Backend directory structure ==="
fd -t f -d 3 "." backend/ | head -30
echo ""
echo "=== Search for @google/genai references in codebase ==="
rg "@google/genai" -n
Length of output: 2896
This file cannot function in the backend environment—backend is Python-based with no Node.js infrastructure.
The backend uses Python (requires.txt, init.py, main.py) but backend/app/gemini_client.js is a JavaScript file requiring the NPM package @google/genai. There is:
- No
backend/package.jsonto manage Node.js dependencies - No root
package.json - No
yarn.lockorpnpm-lock.yaml
The @google/genai package cannot be installed or executed in this backend. This file either belongs in the frontend/ directory (which has a package.json) or the backend needs a complete Node.js setup with its own package.json and dependency management.
🤖 Prompt for AI Agents
In backend/app/gemini_client.js lines 1-6, this JavaScript Gemini client imports
an NPM package and cannot run in the Python-only backend; either move this file
to the frontend (which has package.json) or convert/remove it and implement an
equivalent Python Gemini client in the backend. To fix: if the client belongs to
the frontend, relocate the file to frontend/src (or similar) and ensure
frontend/package.json lists @google/genai; if it belongs in the backend, delete
this JS file and add a Python implementation using the appropriate Google GenAI
Python SDK or HTTP calls, update backend requirements and imports, and remove
any references to the JS module.
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (5)
guides/summaries/GEMINI_API_IMPLEMENTATION_GUIDE.md (1)
32-33: Add language specifiers to code blocks.The code blocks at lines 32-33 and 56-57 lack language specifiers, reducing syntax highlighting and accessibility.
Apply these diffs:
Lines 32-33:
- ``` + ```bash GEMINI_API_KEY="your-gemini-api-key" ```Lines 56-57:
- ``` + ```bash NEXT_PUBLIC_API_URL="http://localhost:8000" ```As per coding guidelines (markdownlint MD040).
Also applies to: 56-57
frontend/lib/geminiApi.ts (1)
1-23: LGTM! This is the correct security pattern for Gemini integration.This implementation properly:
- ✅ Uses backend proxy to keep API key server-side
- ✅ Validates environment configuration early
- ✅ Handles errors with meaningful context
- ✅ Sets appropriate request headers
This approach should be the canonical pattern for all Gemini API interactions from the frontend, as documented in
GEMINI_API_IMPLEMENTATION_GUIDE.md.Optional improvement: Consider adding a TypeScript interface for the return type instead of
Promise<any>:interface GeminiResponse { candidates?: Array<{ content: { parts: Array<{ text: string }>; role: string; }; }>; // Add other fields as needed } export async function generateGeminiText(prompt: string): Promise<GeminiResponse> { // ... existing implementation }This provides better type safety for consumers of this function.
backend/.env.example (1)
5-5: Reorganize GEMINI_API_KEY to AI Configuration section.The
GEMINI_API_KEYis placed at line 5 (near the top), but other AI-related keys (GROQ_API_KEY,AI_API_KEY) are grouped under the "AI Configuration" comment at lines 16-18. This inconsistency makes the file harder to maintain.Apply this diff to group AI configuration keys together:
# Application Settings APP_NAME=InPactAI -GEMINI_API_KEY=your-gemini-api-key-here # Supabase Configuration SUPABASE_URL=https://yoursupabaseurl.supabase.co SUPABASE_KEY=your-supabase-anon-key-here# AI Configuration +GEMINI_API_KEY=your-gemini-api-key-here GROQ_API_KEY=your-groq-api-key AI_API_KEY=your-openai-api-key-optionalbackend/app/api/routes/gemini_generate.py (2)
1-1: Remove unused import.The
osmodule is imported but never used in this file.Apply this diff:
-import os import requests from fastapi import APIRouter, HTTPException from pydantic import BaseModel from app.core.config import settings
28-29: Improve exception handling with chaining and remove redundant conversion.Two improvements flagged by static analysis:
- Exception chaining: Use
raise ... from eto preserve the original traceback for debugging- Redundant conversion: f-strings automatically convert objects to strings, so
str(e)is unnecessaryApply this diff:
except requests.RequestException as e: - raise HTTPException(status_code=502, detail=f"Gemini API error: {str(e)}") + raise HTTPException(status_code=502, detail=f"Gemini API error: {e}") from eBenefits:
from epreserves the full exception chain for better debugging in logs- Removing
str()is cleaner and follows Python best practicesAs per coding guidelines (Ruff B904, RUF010).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
frontend/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (8)
backend/.env.example(1 hunks)backend/app/api/routes/gemini_generate.py(1 hunks)backend/app/core/config.py(1 hunks)backend/app/main.py(2 hunks)frontend/lib/geminiApi.ts(1 hunks)frontend/package.json(1 hunks)frontend/server/geminiClient.ts(1 hunks)guides/summaries/GEMINI_API_IMPLEMENTATION_GUIDE.md(1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
guides/summaries/GEMINI_API_IMPLEMENTATION_GUIDE.md
32-32: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
56-56: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🪛 Ruff (0.14.3)
backend/app/api/routes/gemini_generate.py
29-29: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
29-29: Use explicit conversion flag
Replace with conversion flag
(RUF010)
🔇 Additional comments (2)
backend/app/main.py (1)
7-7: LGTM! Router integration follows existing patterns.The Gemini router is properly imported and registered, following the same pattern used for the existing
healthandauthrouters. The implementation is clean and consistent.Also applies to: 30-30
backend/app/api/routes/gemini_generate.py (1)
15-16: Defensive API key check is good practice.This validation check is appropriate and will be necessary once
gemini_api_keyis madeOptionalinbackend/app/core/config.py(see my comment on that file).Currently, since
gemini_api_keyis defined as required (non-Optional), the application would fail at startup if the key is missing, making this runtime check unreachable. However, keeping this defensive check is good practice for:
- Future-proofing - works correctly when Settings is fixed to Optional
- Clear error messaging - provides specific error about missing configuration
- Defense in depth - guards against unexpected None values
Consider enhancing the error message to be more helpful:
if not GEMINI_API_KEY: - raise HTTPException(status_code=500, detail="GEMINI_API_KEY not set in environment.") + raise HTTPException( + status_code=500, + detail="Gemini API is not configured. Please set GEMINI_API_KEY in backend/.env" + )
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (5)
guides/summaries/GEMINI_API_IMPLEMENTATION_GUIDE.md (2)
32-34: Add language specifier to code block.The fenced code block should specify
envorbashas the language identifier for proper syntax highlighting and better documentation rendering.Apply this diff:
- ``` + ```env GEMINI_API_KEY="your-gemini-api-key" ```
56-58: Add language specifier to code block.The fenced code block should specify
envorbashas the language identifier for proper syntax highlighting and better documentation rendering.Apply this diff:
- ``` + ```env NEXT_PUBLIC_API_URL="http://localhost:8000" ```backend/app/api/routes/gemini_generate.py (3)
1-1: Remove unused import.The
osmodule is imported but never used in this file.Apply this diff:
-import os import requests
7-12: Remove excessive blank lines.Six consecutive blank lines are unnecessary and reduce code readability.
Apply this diff:
- - router = APIRouter()
36-36: Add exception chaining for better error context.When re-raising exceptions within an except clause, use
raise ... from eto preserve the original exception context and traceback, making debugging easier.As per coding guidelines.
Apply this diff:
- raise HTTPException(status_code=502, detail=f"Gemini API error: {str(e)}") + raise HTTPException(status_code=502, detail=f"Gemini API error: {str(e)}") from eNote: This change is also included in the previous comment's diff for the async HTTP client refactor.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
backend/app/api/routes/gemini_generate.py(1 hunks)backend/app/core/config.py(1 hunks)guides/summaries/GEMINI_API_IMPLEMENTATION_GUIDE.md(1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
guides/summaries/GEMINI_API_IMPLEMENTATION_GUIDE.md
32-32: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
56-56: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🪛 Ruff (0.14.3)
backend/app/api/routes/gemini_generate.py
36-36: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
36-36: Use explicit conversion flag
Replace with conversion flag
(RUF010)
🔇 Additional comments (2)
backend/app/core/config.py (1)
17-17: LGTM! Consistent with existing AI service configuration.The
gemini_api_keyfield is now correctly defined as optional, matching the pattern ofai_api_keyandgroq_api_key. This allows the application to start without the Gemini API key and only requires it when the Gemini features are actually used.guides/summaries/GEMINI_API_IMPLEMENTATION_GUIDE.md (1)
43-43: Model identifier is current; no action needed.The current Gemini "Flash" model ID is gemini-2.5-flash, which matches the identifier already in the code. No updates required.
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (5)
backend/app/api/routes/gemini_generate.py (5)
1-1: Remove unused import.The
osmodule is imported but never used in this file.Apply this diff:
-import os import httpx
7-12: Reduce excessive blank lines.Six consecutive blank lines are unnecessary and reduce code readability. PEP 8 recommends at most two blank lines between top-level definitions.
Apply this diff:
- - - router = APIRouter()
15-15: Consider making the Gemini model configurable.The model name
gemini-2.5-flashis hardcoded in the URL. If you need to switch models or test different versions, you'll have to modify the code. Consider moving this to configuration.Option 1: Add to settings (recommended):
In
backend/app/core/config.py:gemini_model: str = "gemini-2.5-flash"Then in this file:
-GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent" +GEMINI_API_URL = f"https://generativelanguage.googleapis.com/v1beta/models/{settings.gemini_model}:generateContent"Option 2: Keep as constant but extract the model name:
+GEMINI_MODEL = "gemini-2.5-flash" -GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent" +GEMINI_API_URL = f"https://generativelanguage.googleapis.com/v1beta/models/{GEMINI_MODEL}:generateContent"
17-18: Add validation constraints to the prompt field.The
promptfield has no validation, which could allow empty strings or excessively long inputs that waste API quota or cause timeouts.Apply this diff to add basic validation:
+from pydantic import BaseModel, Field + class GenerateRequest(BaseModel): - prompt: str + prompt: str = Field(..., min_length=1, max_length=10000, description="User prompt for content generation")Adjust
max_lengthbased on your requirements and Gemini API limits.
20-39: Consider adding operational safeguards for production use.While the basic integration is solid, consider these enhancements for production:
- Rate limiting: Protect against API quota exhaustion and abuse
- Retry logic: Handle transient failures with exponential backoff
- Logging: Track requests, responses, and errors for debugging and monitoring
- Response validation: Ensure the Gemini API response has the expected structure before returning
These can be deferred to future PRs as this PR focuses on foundational setup.
Example retry implementation with
httpx:from tenacity import retry, stop_after_attempt, wait_exponential @retry( stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10), retry=retry_if_exception_type(httpx.RequestError) ) async def call_gemini_api(client, url, **kwargs): response = await client.post(url, **kwargs) response.raise_for_status() return response
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
backend/app/api/routes/gemini_generate.py(1 hunks)backend/requirements.txt(1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.3)
backend/app/api/routes/gemini_generate.py
37-37: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
37-37: Use explicit conversion flag
Replace with conversion flag
(RUF010)
39-39: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
39-39: Use explicit conversion flag
Replace with conversion flag
(RUF010)
🔇 Additional comments (1)
backend/app/api/routes/gemini_generate.py (1)
20-35: Great implementation of async HTTP client!The code now correctly uses
httpx.AsyncClientwith async/await, which addresses the previous review feedback about blocking I/O. The timeout configuration and response handling look good.
📝 Description
This pull request integrates the basic setup for the Gemini API SDK in both backend and frontend environments. It securely configures the Gemini client using environment variables, ensuring the API key is not exposed to the browser. No Gemini-powered features are implemented yet—this is foundational setup only.
🔧 Changes Made
✅ Checklist
Summary by CodeRabbit
New Features
Documentation
Chores